Skip to content

make pydantic optional - #6786

Merged
masenf merged 8 commits into
reflex-dev:mainfrom
benedikt-bartscher:make-pydantic-optional
Aug 6, 2026
Merged

make pydantic optional#6786
masenf merged 8 commits into
reflex-dev:mainfrom
benedikt-bartscher:make-pydantic-optional

Conversation

@benedikt-bartscher

Copy link
Copy Markdown
Contributor

No description provided.

@codspeed-hq

codspeed-hq Bot commented Jul 16, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 26 untouched benchmarks
⏩ 8 skipped benchmarks1


Comparing benedikt-bartscher:make-pydantic-optional (02f7152) with main (7ba00b4)

Open in CodSpeed

Footnotes

  1. 8 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@greptile-apps

greptile-apps Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR makes pydantic an optional dependency of both reflex and reflex-base. The hot-path pydantic check in base_state_processor.py is moved from per-call find_spec to a single module-level probe (with the result cached as BaseModelV2 = None when absent), which is a good performance improvement. A new subprocess-based test verifies that core import, state, component render, and serializer functionality all work without pydantic present.

  • packages/reflex-base/pyproject.toml: pydantic removed from hard deps, added as [project.optional-dependencies] pydantic.
  • pyproject.toml: new pydantic = ["reflex-base[pydantic]"] extra; db extra retains a direct pydantic pin.
  • tests/units/test_optional_pydantic.py: subprocess test with sys.meta_path filter + sys.modules purge to simulate a pydantic-free environment.

Confidence Score: 5/5

  • This PR is safe to merge — the changes are narrowly scoped to dependency declarations and a single import-time guard, with no functional regressions for users who have pydantic installed.
  • The pydantic guard is moved from per-call to module-level with a clear null sentinel, the test simulates a pydantic-free environment correctly (including the sys.modules purge that was previously missing), and the breaking change is documented. No defects were found in the changed paths.
  • No files require special attention.

Important Files Changed

Filename Overview
packages/reflex-base/src/reflex_base/event/processor/base_state_processor.py Moves the pydantic find_spec check from per-event to module-import time, setting BaseModelV2 = None when pydantic is absent; hot-path guard is correct and well-commented.
packages/reflex-base/pyproject.toml Moves pydantic from hard dependency to [project.optional-dependencies]; version constraint preserved.
pyproject.toml Adds pydantic = ["reflex-base[pydantic]"] extra; db extra keeps pydantic as a direct dependency.
tests/units/test_optional_pydantic.py New subprocess-based test that blocks pydantic via sys.meta_path filter + sys.modules purge, verifying core reflex functionality works without pydantic; well-structured isolation mechanism.
news/+pydantic-optional.breaking.md Breaking change note documenting the removal of pydantic as a hard dependency and the new reflex[pydantic] extra.
uv.lock Lockfile updated to reflect pydantic becoming optional; also includes an aiohttp version downgrade from 3.14.3 to 3.14.1.

Reviews (8): Last reviewed commit: "Resolve pydantic presence once instead o..." | Re-trigger Greptile

Comment thread tests/units/test_optional_pydantic.py

@masenf masenf left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interesting; i thought we had pydantic as optional for some time now, but i guess not...

@benedikt-bartscher
benedikt-bartscher marked this pull request as ready for review July 17, 2026 16:35
@benedikt-bartscher
benedikt-bartscher requested a review from a team as a code owner July 17, 2026 16:35
@benedikt-bartscher

Copy link
Copy Markdown
Contributor Author

interesting; i thought we had pydantic as optional for some time now, but i guess not...

I remember reading some git commits or changelogs which mentioned this as well - however somehow it currently isn't optional.

I guess this is ready for review now.

benedikt-bartscher and others added 5 commits July 17, 2026 18:46
With pydantic optional, find_spec("pydantic") in _transform_event_arg
does a full sys.path scan on every dict-payload argument when pydantic
is absent (measured 85us per call; 0.64us after hoisting). Bind the
BaseModel reference once at import, like the other guarded sites.
@FarhanAliRaza

Copy link
Copy Markdown
Contributor

Validated this end to end in a real app: installed the branch's packages into a clean venv (confirmed nothing pulls pydantic transitively — 40 packages, no pydantic), ran a counter app, and exercised state events in the browser — compile, hydration, and event round-trips all work without pydantic. Also confirmed the [pydantic] extra resolves and re-activates model serialization / MUTABLE_TYPES / ObjectVar support.

One perf issue surfaced and is fixed in 02f7152: _transform_event_arg called find_spec("pydantic") per dict-payload event argument. That was harmless while pydantic was a hard dep (sys.modules hit, ~125ns), but with pydantic absent every call did a full sys.path scan — measured 85.3µs per argument, and 0.64µs after hoisting the check to import time like the other guarded sites.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 7 files

Re-trigger cubic

@masenf
masenf merged commit d8a132b into reflex-dev:main Aug 6, 2026
108 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants